package Presenter;

import Constraints.IConstraint;
import Core.ErrorMessage;
import Exceptions.ConstraintErrorException;
import Factory.IConstraintFactory;
import Factory.Impl.ConstraintFactory;
import Model.Core.IMachineStateElement;
import Model.Core.Impl.State;
import Model.Core.Impl.Transition;
import Model.Core.Tip.TipMoment;
import Model.Core.Tip.TipType;
import Model.Diagrams.StateMachine;
import Model.Draw.Entities.StateDraw;
import Model.Draw.Events.ManifestElementEvent;
import Model.Draw.Events.ManifestStateDoneListener;
import Model.Draw.IDraw;
import Model.Draw.IMachineStateDraw;
import Model.Draw.Point;
import Services.IDrawService;
import Services.Impl.DrawService;
import ViewInterfaces.IStateMachineDrawView;
import java.util.ArrayList;
import java.util.List;

/**
 * Projeto de TCC: Editor de Diagramas de comunicação BlueJ
 * @author Jose
 */
public class StateMachinePresenter implements ManifestStateDoneListener {

    private IStateMachineDrawView view;
    private IDrawService drawService;
    private IConstraintFactory constraintFactory;
    private StateMachine currentStateMachine;

    public StateMachinePresenter(IStateMachineDrawView stateMachineView) {
        view = stateMachineView;
        drawService = new DrawService();
        constraintFactory = new ConstraintFactory();
    }

    public void stateSelected() {
        State state = new State();
        state.addGraphicalManifestListener(this);
        drawService.setCurrentElement(state);
        drawService.configureContraint(constraintFactory.getStateConstraint());
    }

    public void transitionSelected() {
        Transition transition = new Transition();
        transition.addGraphicalManifestListener(this);
        drawService.setCurrentElement(transition);
        drawService.configureContraint(constraintFactory.getTransitionConstraint());
    }

    public void newEntry(Point point) {
        List<IMachineStateDraw> draws = view.tryGetStateDrawAt(point);
        view.selectStateFrom(point);
        IMachineStateElement stateElement = null;
        if (draws.size() >= 1) {
            stateElement = findStateElementWithDraw(draws.get(0));
            view.showMessage(stateElement.findTipBy(TipType.Action, TipMoment.Selection).getMessage(), false);
        } else {
            view.cleanMessage();
        }
        updateCanvas();
        try {
            drawService.newEntry(stateElement == null ? point : stateElement);
        } catch (ConstraintErrorException ex) {
            view.showMessage(ex.getMessage(), true);
        }
    }

    public void updateCanvas() {
        view.updateStateCanvas();
    }

    public void unselectAll() {
    }

    public void setCurrentStateMachine(StateMachine currentStateMachine) {
        this.currentStateMachine = currentStateMachine;
        view.setStateDrawList(getAllStateDrawsOf(currentStateMachine));
    }

    private IMachineStateElement findStateElementWithDraw(IMachineStateDraw stateDraw) {
        for (IMachineStateElement stateElement : currentStateMachine.getStatesElements()) {
            if (stateElement.getDraw() == stateDraw) {
                return stateElement;
            }
        }
        return null;
    }

    @Override
    public void manifestStateDoneHandler(ManifestElementEvent e) {
        IMachineStateElement stateElement = (IMachineStateElement) e.getSource();
        view.manifestStateDraw(stateElement.getDraw());
        view.saveDraw(stateElement.getDraw());
        currentStateMachine.addStateElements(stateElement);
    }

    public void configureContext() {
        view.configureStateContext();
    }

    public void StartRename(IMachineStateDraw entityDrawSelected) {
        view.setRenameDraw(entityDrawSelected);
        view.showMessage(findStateElementWithDraw(entityDrawSelected).findTipBy(TipType.Action, TipMoment.Rename).getMessage(), false);
        view.showRenameField(true);
        updateCanvas();
    }

    public void StartMoveEntity(IMachineStateDraw selectedDraw) {
        if (selectedDraw instanceof StateDraw) {
            view.enableMoving(true);
            view.showMessage(findStateElementWithDraw(selectedDraw).findTipBy(TipType.Action, TipMoment.Move).getMessage(), false);
        }
    }

    public void RenameEntity(IMachineStateDraw draw, String text) {
        IConstraint constraint = constraintFactory.getStateMachineContraint();

        List<ErrorMessage> errors = constraint.Validate(new Object[]{currentStateMachine, draw, text});
        if (errors == null) {
            draw.rename(text);
            view.cleanMessage();
            view.showRenameField(false);
            updateCanvas();
        } else {
            StringBuilder msgError = new StringBuilder();
            for (ErrorMessage error : errors) {
                msgError.append(error.getMessage());
            }
            view.showMessage(msgError.toString(), true);
        }
    }

    private List<IMachineStateDraw> getAllStateDrawsOf(StateMachine stateMachine) {
        List<IMachineStateDraw> draws = new ArrayList<IMachineStateDraw>();
        for (IMachineStateElement state : stateMachine.getStatesElements()) {
            draws.add(state.getDraw());
        }
        return draws;
    }

    public void moveDraw(IMachineStateDraw draw, Point clickedPoint) {
        draw.move((int) clickedPoint.getX().getCoordinate(), (int) clickedPoint.getY().getCoordinate());
        view.enableMoving(false);
        view.cleanMessage();
        view.showRenameField(false);
        updateCanvas();
    }
}